<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D 赛博躲避游戏 - Three.js Demo</title>
    <style>
        body { margin: 0; overflow: hidden; font-family: 'Courier New', Courier, monospace; }
        #ui {
            position: absolute;
            top: 20px;
            left: 0;
            width: 100%;
            text-align: center;
            color: #00ffcc;
            pointer-events: none; /* 让鼠标事件穿透UI层 */
            z-index: 10;
        }
        h1 { text-shadow: 0 0 10px #00ffcc; font-size: 24px; margin: 0; }
        p { font-size: 14px; color: white; }
        #score-board { font-size: 40px; font-weight: bold; text-shadow: 2px 2px 0px #ff0066; }
        #game-over {
            display: none;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.8);
            padding: 20px;
            border: 2px solid #ff0066;
            text-align: center;
            color: white;
            pointer-events: auto;
            cursor: pointer;
        }
    </style>
</head>
<body>

    <div id="ui">
        <h1>CYBER DODGE 3D</h1>
        <p>移动鼠标控制方块，避开红色障碍</p>
        <div id="score-board">0</div>
    </div>

    <div id="game-over">
        <h2 style="color: #ff0066;">GAME OVER</h2>
        <p>点击此处重新开始</p>
    </div>

    <script type="importmap">
        {
            "imports": {
                "three": "https://unpkg.com/three@0.160.0/build/three.module.js"
            }
        }
    </script>

    <script type="module">
        import * as THREE from 'three';

        // --- 1. 初始化场景 ---
        const scene = new THREE.Scene();
        scene.background = new THREE.Color(0x111111); // 深色背景
        scene.fog = new THREE.Fog(0x111111, 10, 50);  // 添加雾效，增加深邃感

        // --- 2. 相机设置 ---
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        camera.position.set(0, 3, 8); // 相机放在玩家后上方
        camera.lookAt(0, 0, 0);

        // --- 3. 渲染器设置 ---
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.enabled = true;
        document.body.appendChild(renderer.domElement);

        // --- 4. 灯光 ---
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
        scene.add(ambientLight);
        
        const dirLight = new THREE.DirectionalLight(0xffffff, 1);
        dirLight.position.set(5, 10, 7);
        dirLight.castShadow = true;
        scene.add(dirLight);

        // --- 5. 游戏对象 ---
        
        // 地面 (赛博网格)
        const gridHelper = new THREE.GridHelper(100, 50, 0x00ffcc, 0x444444);
        scene.add(gridHelper);

        // 地板平面 (用于接收阴影)
        const planeGeometry = new THREE.PlaneGeometry(100, 100);
        const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x111111 });
        const plane = new THREE.Mesh(planeGeometry, planeMaterial);
        plane.rotation.x = -Math.PI / 2;
        plane.position.y = -0.1;
        plane.receiveShadow = true;
        scene.add(plane);

        // 玩家 (霓虹方块)
        const playerGeo = new THREE.BoxGeometry(1, 1, 1);
        const playerMat = new THREE.MeshStandardMaterial({ color: 0x00ffcc, emissive: 0x004444 });
        const player = new THREE.Mesh(playerGeo, playerMat);
        player.position.y = 0.5;
        player.castShadow = true;
        scene.add(player);

        // 障碍物数组
        let obstacles = [];
        const obstacleSpeed = 0.2;
        
        // 粒子效果 (星星)
        const starsGeo = new THREE.BufferGeometry();
        const starsCount = 500;
        const posArray = new Float32Array(starsCount * 3);
        for(let i = 0; i < starsCount * 3; i++) {
            posArray[i] = (Math.random() - 0.5) * 100;
        }
        starsGeo.setAttribute('position', new THREE.BufferAttribute(posArray, 3));
        const starsMat = new THREE.PointsMaterial({size: 0.1, color: 0xffffff});
        const starMesh = new THREE.Points(starsGeo, starsMat);
        scene.add(starMesh);

        // --- 6. 游戏逻辑变量 ---
        let score = 0;
        let isGameOver = false;
        const scoreElement = document.getElementById('score-board');
        const gameOverElement = document.getElementById('game-over');

        // --- 7. 控制逻辑 (鼠标跟随) ---
        const mouse = new THREE.Vector2();
        const targetPos = new THREE.Vector3();

        window.addEventListener('mousemove', (event) => {
            if (isGameOver) return;
            
            // 将鼠标坐标归一化到 -1 到 1
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            
            // 限制玩家移动范围 (-5 到 5)
            targetPos.x = mouse.x * 6; 
        });

        // 重新开始
        gameOverElement.addEventListener('click', () => {
            resetGame();
        });

        function resetGame() {
            isGameOver = false;
            score = 0;
            scoreElement.innerText = score;
            gameOverElement.style.display = 'none';
            
            // 清除所有障碍物
            obstacles.forEach(obj => scene.remove(obj));
            obstacles = [];
            
            player.position.set(0, 0.5, 0);
        }

        function createObstacle() {
            const geo = new THREE.BoxGeometry(1, 1, 1);
            // 随机红色系颜色
            const mat = new THREE.MeshStandardMaterial({ color: 0xff0066, emissive: 0x440022 }); 
            const mesh = new THREE.Mesh(geo, mat);
            
            // 随机位置 (x: -5 ~ 5, z: -50)
            mesh.position.x = (Math.random() - 0.5) * 12;
            mesh.position.y = 0.5;
            mesh.position.z = -50;
            mesh.castShadow = true;
            
            scene.add(mesh);
            obstacles.push(mesh);
        }

        // --- 8. 动画循环 (核心逻辑) ---
        let frameCount = 0;

        function animate() {
            requestAnimationFrame(animate);

            if (isGameOver) return;

            // 1. 玩家平滑移动
            player.position.x += (targetPos.x - player.position.x) * 0.1;
            // 玩家轻微旋转动画
            player.rotation.z = (player.position.x - targetPos.x) * 0.1;
            player.rotation.x += 0.02;

            // 2. 障碍物生成与移动
            frameCount++;
            // 每 40 帧生成一个障碍物 (随着分数增加可以变快，这里简化处理)
            if (frameCount % 40 === 0) {
                createObstacle();
            }

            // 3. 星空背景移动效果
            starMesh.rotation.z += 0.001;

            // 4. 遍历障碍物
            for (let i = obstacles.length - 1; i >= 0; i--) {
                const obj = obstacles[i];
                obj.position.z += 0.4 + (score * 0.001); // 随分数增加速度
                obj.rotation.x += 0.05;
                obj.rotation.y += 0.05;

                // 碰撞检测 (简单的距离检测)
                const dist = player.position.distanceTo(obj.position);
                if (dist < 1.0) {
                    isGameOver = true;
                    gameOverElement.style.display = 'block';
                }

                // 超出屏幕移除并加分
                if (obj.position.z > 10) {
                    scene.remove(obj);
                    obstacles.splice(i, 1);
                    score++;
                    scoreElement.innerText = score;
                }
            }
            
            // 移动地面网格模拟前进效果
            gridHelper.position.z = (gridHelper.position.z + 0.2) % 10;

            renderer.render(scene, camera);
        }

        // --- 9. 窗口自适应 ---
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });

        // 开始动画
        animate();

    </script>
</body>
</html>